﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Globalization;


namespace QuickWPFMonthCalendar.UserControls
{

    public delegate void DisplayMonthChanged(object sender, MonthChangedEventArgs e);

    /// <summary>
    /// MonthView.xaml の相互作用ロジック
    /// </summary>
    public partial class MonthView : UserControl
    {

        public event DisplayMonthChanged _DisplayMonthChanged; 
        private CultureInfo _cultureInfo = new CultureInfo(CultureInfo.CurrentUICulture.LCID);
        public DateTime _DisplayStartDate = DateTime.Now.AddDays(-1 * (DateTime.Now.Day - 1));
        public int _DisplayMonth;
        public int _DisplayYear;
        private int iday = 0;

        public MonthView()
        {
            InitializeComponent();

        }


        public DateTime DisplayStartDate
        {
            get
            {
                return _DisplayStartDate;
            }
            set
            {
                _DisplayStartDate = value;
                _DisplayMonth = _DisplayStartDate.Month;
                _DisplayYear = _DisplayStartDate.Year;
            }
        }

        private List<Appointment> _monthAppointments = new List<Appointment>();
        public List<Appointment> MonthAppointments
        {
            get { return _monthAppointments; }
            set
            {
                _monthAppointments = value;
                BuildCalendarUI();
            }
        }

        private void BuildCalendarUI()
        {
            _DisplayMonth = _DisplayStartDate.Month;
            _DisplayYear = _DisplayStartDate.Year;

            int iDaysInMonth = _cultureInfo.Calendar.GetDaysInMonth(_DisplayStartDate.Year, _DisplayStartDate.Month);
            int iOffsetDays = (int)(System.Enum.ToObject(typeof(System.DayOfWeek), _DisplayStartDate.DayOfWeek));
            int iWeekCount = 0;
            WeekOfDaysControls weekRowCtrl = new WeekOfDaysControls();

            MonthViewGrid.Children.Clear();
            AddRowsToMonthGrid(iDaysInMonth, iOffsetDays);
            MonthYearLabel.Content = _DisplayMonth.ToString() + " " + _DisplayYear;

            for (int i = 1; i <= iDaysInMonth; i++)
            {
                if ((i != 1) && System.Math.IEEERemainder((i + iOffsetDays - 1), 7) == 0)
                {
                    // add existing weekrowcontrol to the monthgrid
                    Grid.SetRow(weekRowCtrl, iWeekCount);
                    MonthViewGrid.Children.Add(weekRowCtrl);
                    //'-- make a new weekrowcontrol
                    weekRowCtrl = new WeekOfDaysControls();
                    iWeekCount += 1;
                }


                //'-- load each weekrow with a DayBoxControl whose label is set to day number
                DayBoxControl dayBox = new DayBoxControl();
                dayBox.DayNumberLabel.Content = i.ToString();
                dayBox.Tag = i;
                //AddHandler dayBox.MouseDoubleClick, AddressOf DayBox_DoubleClick

                // '-- customize daybox for today:
                if ((new DateTime(_DisplayYear, _DisplayMonth, i)) == DateTime.Today)
                {
                    dayBox.DayLabelRowBorder.Background = (Brush)(dayBox.TryFindResource("OrangeGradientBrush"));
                    dayBox.DayAppointmentsStack.Background = Brushes.Wheat;
                }

                if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
                {
                    Random Rnd = new Random();
                    if (Rnd.Next(1) < 0.25)
                    {
                        DayBoxAppointmentControl apt = new DayBoxAppointmentControl();
                        apt.DisplayText.Text = "Apt on " + i + "th";
                        dayBox.DayAppointmentsStack.Children.Add(apt);
                    }
                }
                else if (_monthAppointments != null)
                {
                    //'-- Compiler warning about unpredictable results if using i (the iterator) in lambda, the 
                    //'   "hint" suggests declaring another var and set equal to iterator var
                    iday = i;
                    List<Appointment> aptInDay = _monthAppointments.FindAll(new System.Predicate<Appointment>(FindComputer));
                    foreach (Appointment a in aptInDay)
                    {
                        DayBoxAppointmentControl apt = new DayBoxAppointmentControl();
                        apt.DisplayText.Text = a.Subject;
                        apt.Tag = a.AppointmentID;
                        //AddHandler apt.MouseDoubleClick, AddressOf Appointment_DoubleClick
                        dayBox.DayAppointmentsStack.Children.Add(apt);
                    }
                }

                Grid.SetColumn(dayBox, (i - (iWeekCount * 7)) + iOffsetDays);
                weekRowCtrl.WeekRowGrid.Children.Add(dayBox);

            }
            Grid.SetRow(weekRowCtrl, iWeekCount);
            MonthViewGrid.Children.Add(weekRowCtrl);
        }


        // Explicit predicate delegate.
        private bool FindComputer(Appointment apt)
        {
            if (apt.StartTime.Day == iday)
                return true;
            else
                return false;

        }

        private void AddRowsToMonthGrid(int DaysInMonth, int OffSetDays)
        {
            MonthViewGrid.RowDefinitions.Clear();

            GridLength rowHeight = new GridLength(60, System.Windows.GridUnitType.Star);

            int EndOffSetDays = 7 - ((int)((System.Enum.ToObject(typeof(System.DayOfWeek), _DisplayStartDate.AddDays(DaysInMonth - 1).DayOfWeek))) + 1);

            for (int i = 1; i <= (int)(DaysInMonth + OffSetDays + EndOffSetDays) / 7; i++)
            {
                RowDefinition rowDef = new RowDefinition();
                rowDef.Height = rowHeight;
                MonthViewGrid.RowDefinitions.Add(rowDef);
            }
        }


           private void UpdateMonth(int MonthsToAdd )
           {
        var ev =new MonthChangedEventArgs();
        ev.OldDisplayStartDate = _DisplayStartDate;
        this.DisplayStartDate = _DisplayStartDate.AddMonths(MonthsToAdd);
        ev.NewDisplayStartDate = _DisplayStartDate;
        if (_DisplayMonthChanged != null)
        {
            _DisplayMonthChanged(this, ev);
        }
                }

        private void MonthGoNext_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            UpdateMonth(1);
        }

        private void MonthGoPrev_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            UpdateMonth(-1);
        }
    }


    public  struct  MonthChangedEventArgs 
    {
    public DateTime OldDisplayStartDate;
    public DateTime NewDisplayStartDate;
    }

}
